﻿/*  Simple Set class for .net framework
    Copyright (C) 2011  Farid Bekran http://developer.ba-da.ir/

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

	*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;


namespace SimpleSet
{
    /// <summary>
    /// Simple set class
    /// </summary>
    public class Set
    {
        /// <summary>
        /// Universe of Current Set object 
        /// U most be assigned to use Set class
        /// </summary>
        public Universe U { get; set;}
        /// <summary>
        /// This property saves values of current set obejct in HashTable instance
        /// </summary>
        private Hashtable Values { get; set; }
        /// <summary>
        /// Private property
        /// </summary>
        private List<string> SetItems
        {
            set {
                InsertSetItems(value);
            }
            
        }
        /// <summary>
        /// Creates an object of Set class with only Universe object
        /// </summary>
        /// <remarks>This method used by internal methods of Set class.</remarks>
        /// <param name="_u"></param>
        private Set(Universe _u)
        {
            if (_u == null)
            {
                throw new ArgumentNullException("Universe can not be NULL.");
            }
            U = _u;
            Values = U.Clone();
        }

        /// <summary>
        /// Creates an instance of Set class with Universe and Values of Set.
        /// </summary>
        /// <remarks>This method is used for external instance creation.</remarks>
        /// <param name="_u">Universe</param>
        /// <param name="_set">Values</param>
        public Set(Universe _u, List<string> _set)
        {
            if (_u == null || _set == null)
            {
                throw new ArgumentNullException("Universe Or set can not be NULL.");
            }
            U = _u;
            Values = U.Clone();

            InsertSetItems(_set);

        }
        private void InsertSetItems(List<string> _setItems)
        {
            // if set items are not in universe that items not added to boolean map of set value...
            _setItems = _setItems.Distinct<string>().ToList<string>();

            foreach (string _setItem in _setItems)
            {
                try
                {
                    Values[_setItem] = true;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }


        
        /// <summary>
        /// Union operator
        /// <example>
        /// Example: Set Union = set1 | set2;
        /// </example>
        /// </summary>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1"></param>
        /// <param name="set2"></param> 
        /// <returns>Set</returns>
        public static Set operator |(Set set1, Set set2)
        {
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            Set temp = new Set(set2.U);
            foreach (DictionaryEntry Dicitem in set1.Values)
            {
                bool Val = (bool)Dicitem.Value || (bool)set2.Values[Dicitem.Key];
                temp.Values[Dicitem.Key] = Val;
            }
            return temp;
        }
        /// <summary>
        /// intersection operator 
        /// </summary>
        /// <example> Example: Set intersection = set1 & set2; </example>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1">Set</param>
        /// <param name="set2">Set</param>
        /// <returns>Set</returns>
        public static Set operator &(Set set1, Set set2)
        {
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            Set temp = new Set(set2.U);
            foreach (DictionaryEntry Dicitem in set1.Values)
            {
                bool Val = (bool)Dicitem.Value && (bool)set2.Values[Dicitem.Key];
                temp.Values[Dicitem.Key] = Val;
            }
            return temp;
        }

        /// <summary>
        /// Exclusive Or operator
        /// <example>
        /// Example: Set ExclusiveOr = set1 ^ set2;
        /// </example>
        /// </summary>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1">Set</param>
        /// <param name="set2">Set</param>
        /// <returns>Set</returns>
        public static Set operator ^(Set set1, Set set2)
        {
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            Set temp = new Set(set2.U);
            foreach (DictionaryEntry Dicitem in set1.Values)
            {
                bool Val = (bool)Dicitem.Value ^ (bool)set2.Values[Dicitem.Key];
                temp.Values[Dicitem.Key] = Val;
            }
            return temp;
        }

        /// <summary>
        /// Inequality Operator
        /// <example>
        /// Example: ... 
        /// if(Set set1 != Set set2)
        /// ...
        /// </example>
        /// </summary>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1">Set</param>
        /// <param name="set2">Set</param>
        /// <returns>Set</returns>
        public static bool operator !=(Set set1, Set set2)
        {
            bool temp = true;
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            foreach (DictionaryEntry Dicitem in set1.Values)
            {
                if ((bool)Dicitem.Value != (bool)set2.Values[Dicitem.Key])
                {
                    temp = false;
                    break;
                }
            }
            return !temp;
        }

        /// <summary>
        /// Equality Operator
        /// <example>
        /// Example: ... if(Set set1 == Set set2) ...
        /// </example>
        /// </summary>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1">Set</param>
        /// <param name="set2">Set</param>
        /// <returns>Set</returns>
        public static bool operator ==(Set set1, Set set2)
        {
            bool temp = true;
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            foreach (DictionaryEntry Dicitem in set1.Values)
            {
                if ((bool)Dicitem.Value != (bool)set2.Values[Dicitem.Key])
                {
                    temp = false;
                    break;
                }
            }
            return temp;
        }

        /// <summary>
        /// minus operator -> A - B = A&(~B)
        /// <example>
        /// Example: Set A_B = set1 - set2;
        /// </example>
        /// </summary>
        /// <remarks>Universe Object most be equal.</remarks>
        /// <param name="set1">Set</param>
        /// <param name="set2">Set</param>
        /// <returns>Set</returns>
        public static Set operator -(Set set1, Set set2)
        {
            if (set1.U != set2.U)
            {
                throw new ArgumentException("Universes most be equal.");
            }
            Set temp = new Set(set1.U);
            temp = set1 & (~set2);
            return temp;
        }

        /// <summary>
        /// complementary operator
        /// <example>
        /// Example: Set Com = ~set1;
        /// </example>
        /// </summary>
        /// <param name="set1">Set</param>
        /// <returns>Set</returns>
        public static Set operator ~(Set set1)
        {
            Set temp = new Set(set1.U);
            foreach (DictionaryEntry item in set1.Values)
            {
                if ((bool)item.Value == false)
                {
                    temp.Values[item.Key] = true;
                }
                else
                {
                    temp.Values[item.Key] = false;
                }
            }
            return temp;
        }

        public override string ToString()
        {
            //return base.ToString();
            string temp = string.Empty;
            bool first = false;
            bool second = false;
            temp += "{";
            
            foreach (DictionaryEntry dicItemp in this.Values)
            {
                if ((bool)dicItemp.Value == true)
                {
                    temp += " " + dicItemp.Key.ToString() + " ";
                }
                
            }
            temp += "}";
            return temp;
        }
        /// <summary>
        /// Add new Item to current Set object
        /// </summary>
        /// <param name="item">string</param>
        public void Add(string item)
        {
            try
            {
                this.Values[item] = true;
            }
            catch (Exception er)
            {
                
                throw er;
            }
        }

        /// <summary>
        /// Delete an item from current Set object
        /// </summary>
        /// <param name="item">string</param>
        public void Delete(string item)
        {
            try
            {
                this.Values[item] = false;
            }
            catch (Exception er)
            {

                throw er;
            }
        }
    }
   
}
